#ifndef _imageStorageTmpl_h_
#define _imageStorageTmpl_h_

// imageStorageTmpl.h
//
// Image storage template class

#include "image/imageStorage.h"
#include <iterator>
#include <typeinfo>

namespace simple{
    //
    // RowIterator
    //
    // iterator class for ImageStorage Forward and reverse
    // operations are allowed.
    template<class T> class RowIterator
    {
    public:
    struct current
    {
        T*  p;      // Pointer to start of row y
        int x;      // x coordinate of start of row
        int y;      // y coordinate of current row
        int bytes;  // Number of bytes to offset to next row
    };

    RowIterator () 
    { _cur.p = 0; _cur.x = 0; _cur.y = 0; _cur.bytes = 0;}
    RowIterator (T* p, int bytes, int x, int y) 
    { _cur.p = p; _cur.bytes = bytes; _cur.x = x; _cur.y = y;}

    current*       operator->()       { return &_cur;}
    const current* operator->() const { return &_cur;}
    current&       operator* ()       { return _cur;}
    const current& operator* () const { return _cur;}

    RowIterator& operator++ ()
    { 
        _cur.p = reinterpret_cast<T*>
            (reinterpret_cast<Pel8*>(_cur.p) + _cur.bytes);
        _cur.y++;
        return *this;
    }
    RowIterator operator++ (int)
    {
        RowIterator t = *this;
        _cur.p = reinterpret_cast<T*>
            (reinterpret_cast<Pel8*>(_cur.p) + _cur.bytes);
        _cur.y++;
        return t;
    }

    RowIterator& operator-- ()
    { 
        _cur.p = reinterpret_cast<T*>
            (reinterpret_cast<Pel8*>(_cur.p) - _cur.bytes);
        _cur.y--;
        return *this;
    }
    RowIterator operator-- (int)
    {
        RowIterator t = *this;
        _cur.p = reinterpret_cast<T*>
            (reinterpret_cast<Pel8*>(_cur.p) - _cur.bytes);
        _cur.y--;
        return t;
    }

    RowIterator& operator+= (int s)
    { 
        _cur.p = reinterpret_cast<T*>
            (reinterpret_cast<Pel8*>(_cur.p) + s*_cur.bytes);
        _cur.y += s;
        return *this;
    }

    RowIterator& operator-= (int s)
    { 
        _cur.p = reinterpret_cast<T*>
            (reinterpret_cast<Pel8*>(_cur.p) - s*_cur.bytes);
        _cur.y -= s;
        return *this;
    }

    bool operator== (const RowIterator& i) const
    { return (_cur.p == i._cur.p);}
    bool operator!= (const RowIterator& i) const
    { return (_cur.p != i._cur.p);}

    // Default copy constructor and assignment operators ok.
    private:
        current _cur;
    };



    //
    // PixelIterator
    //
    // Pixel iterator class for ImageStorage Forward and reverse
    // operations are allowed. This iterator is suitable when you want
    // to examine all pixels in the image.
    template<class T> class PixelIterator
    {
    public:
        // Standard iteration typedef's
        typedef std::forward_iterator_tag iterator_category;
        typedef T value_type;
        typedef ptrdiff_t difference_type;
        typedef T* pointer;
        typedef T& reference;

        struct current
        {
            T*  p;      // Current pointer to pixel
            int x, y;   // Current pixel coordinates

            T*  end;    // Pointer past last pixel in current row
            int x0;     // x coordinate of start of row
            int width;  // Width of row
            int bytes;  // Number of bytes to offset to next row
        };

        PixelIterator () 
        {
            _cur.p = 0; _cur.x = 0; _cur.y = 0;
            _cur.end = 0; _cur.x0 = 0;
            _cur.width = 0; _cur.bytes = 0;
        }
        PixelIterator (T* p, int bytes, int x, int y, int width) 
        { 
            _cur.p     = p;
            _cur.x     = x;
            _cur.y     = y;
            _cur.x0    = x;
            _cur.bytes = bytes;
            _cur.width = width;
            _cur.end   = _cur.p + _cur.width;
        }

        T*       operator->()       { return _cur.p;}
        const T* operator->() const { return _cur.p;}
        T&       operator* ()       { return *_cur.p;}
        const T& operator* () const { return *_cur.p;}

        PixelIterator& operator++ ()
        { 
            _cur.x++;
            _cur.p++;
            if (_cur.p >= _cur.end) {
                // Advance to the next row
                _cur.x = _cur.x0;
                _cur.y++;
                _cur.p = reinterpret_cast<T*>(
                    reinterpret_cast<Pel8*>(_cur.p)
                    + _cur.bytes - _cur.width*sizeof(T));
                _cur.end = _cur.p + _cur.width;
            }
      
            return *this;
        }

        PixelIterator operator++ (int)
        { 
            PixelIterator t = *this;

            _cur.x++;
            _cur.p++;
            if (_cur.p >= _cur.end) {
                // Advance to the next row
                _cur.x = _cur.x0;
                _cur.y++;
                _cur.p = reinterpret_cast<T*>(reinterpret_cast<Pel8*>(_cur.p)
                    + _cur.bytes - _cur.width*sizeof(T));
                _cur.end = _cur.p + _cur.width;
            }
          
            return t;
        }

        bool operator== (const PixelIterator& i) const
        { return (_cur.p == i._cur.p);}
        bool operator!= (const PixelIterator& i) const
        { return (_cur.p != i._cur.p);}

        // Default copy constructor and assignment operators ok.
    private:
        current _cur;
    };



    //
    // ImageStorage
    //
    // ImageStorage are template objects constructed by the user.
    // They utilize the capabilities of RectImageStorage to handle
    // memory allocation. Iterators are also added 
    template<class T>
    class ImageStorage : public RectImageStorage
    {
    public:
        typedef RowIterator<T>   row_iterator;
        typedef PixelIterator<T> iterator;

        ImageStorage () {}
        ImageStorage (const Rect& boundary, eAlignment align = eNoAlign) 
            : RectImageStorage (boundary, sizeof (T), align) {}

        const T* rowAddress (int y) const
        { return reinterpret_cast<const T*> (_rowAddress (y));}
        T* rowAddress (int y)
        { return reinterpret_cast<T*> (_rowAddress (y));}
        // Returns a pointer to the first pixel in the specified row
        // Not thread-safe. Clients need to lock storage
        // Throws BoundsException if the argument is not in range

        const T& getPixel (int x, int y) const;
        const T& getPixel (const Point& point) const 
        { return getPixel (point.x(), point.y());}
        void     setPixel (int x, int y, const T& pixel);
        void     setPixel (const Point& point, const T& pixel)
        { setPixel (point.x(), point.y(), pixel);}
        // Gets or sets the specified pixel. Thread-safe.
        // Throws BoundsException it the argument is not in range

        void setRow (int y, const T& pixel);
        void setCol (int x, const T& pixel);
        // Sets the values of an entire row or column to the specified pixel

        virtual ~ImageStorage () {}

        // row iterators. Not thread-safe. Clients need to lock storage
        row_iterator       row_begin () 
        { return row_iterator 
              (reinterpret_cast<T*>(_begin), rowSpacing(), x0(), y0());}
        const row_iterator row_begin () const
        { return row_iterator 
              (reinterpret_cast<T*>(_begin), rowSpacing(), x0(), y0());}

        row_iterator       row_end () 
        { return row_iterator 
              (reinterpret_cast<T*>(_end), rowSpacing(), x0(), y0());}
        const row_iterator row_end () const
        { return row_iterator 
              (reinterpret_cast<T*>(_end), rowSpacing(), x0(), y0());}

        // pixel iterators. Not thread-safe. Clients need to lock storage
        iterator           begin () 
        { return iterator 
              (reinterpret_cast<T*>(_begin), rowSpacing(), x0(), y0(), width());}
        const iterator     begin () const
        { return iterator 
              (reinterpret_cast<T*>(_begin), rowSpacing(), x0(), y0(), width());}

        iterator           end () 
        { return iterator 
              (reinterpret_cast<T*>(_end), rowSpacing(), x0(), y0(), width());}
        const iterator     end () const
        { return iterator 
              (reinterpret_cast<T*>(_end), rowSpacing(), x0(), y0(), width());}
    };



    //
    // ImageStorageLocker
    //
    // Locking is an important issue in multi-threaded designs. This
    // object will lock/unlock an ImageStorage<> object. Using a 
    // temporary instance of ImageLocker means that the object
    // is unlocked should an exception ever be thrown. The template
    // object must have lock() and unlock() methods. We could have
    // written a very generic object, but it is easy for users to
    // remember to call this because of its name.
    template<class T> class ImageStorageLocker
    {
    public:
        ImageStorageLocker (const ImageStorage<T>& image) : image_ (image) { image_.lock();}
        ~ImageStorageLocker () { image_.unlock();}
    private:
        const ImageStorage<T>& image_;

        // No copy or assignment is allowed
        ImageStorageLocker (const ImageStorageLocker&);
        ImageStorageLocker& operator= (const ImageStorageLocker&);
    };





    template<class T>
    const T& ImageStorage<T>::getPixel (int x, int y) const
    { 
        static T pixel;

        ImageStorageLocker<T> locker (*this); // Exception-safe locking

        const Pel8* p = RectImageStorage::getPixel (x, y);
        memcpy (&pixel, p, sizeof (T));

        return pixel;
    }

    template<class T>
    void ImageStorage<T>::setPixel (int x, int y, const T& pixel)
    { 
        ImageStorageLocker<T> locker (*this); // Exception-safe locking

        const Pel8* p = reinterpret_cast<const Pel8*> (&pixel);
        RectImageStorage::setPixel (x, y, p);
    }

    template<class T>
    void ImageStorage<T>::setRow (int y, const T& pixel)
    {
        ImageStorageLocker<T> locker (*this); // Exception-safe locking

        T* p = rowAddress (y);
        for (unsigned int i=0; i<width(); i++)
            *p++ = pixel;
    }

    template<class T>
    void ImageStorage<T>::setCol (int x, const T& pixel)
    {
        ImageStorageLocker<T> locker (*this); // Exception-safe locking

        T* p = reinterpret_cast<T*>(getAddr (x, y0()));
        // A little more complicated because we step vertically
        for (unsigned int i=0; i<height(); i++) {
            *p = pixel;
            p  = reinterpret_cast<T*> (reinterpret_cast<Pel8*>(p) + rowSpacing_);
        }
    }



    //
    // non-member functions
    //

    template <class T1, class T2>
    void copy (const ImageStorage<T1>& src, ImageStorage<T2>& dst, bool fastCopy = true)
    {
        if (src == dst) return;

        // Exception-safe locking
        ImageStorageLocker<T1> srcLocker (src);

        if (src.boundary() != dst.boundary())
            dst = ImageStorage<T2> (src.boundary(), src.alignment());

        ImageStorageLocker<T2> dstLocker (dst);

        typename ImageStorage<T1>::row_iterator i1;
        typename ImageStorage<T2>::row_iterator i2;
        unsigned int w = src.width ();
        int bytes = w * src.bytesPerPixel ();

        const T1* p1;
        T2* p2;

        if (typeid(T1) == typeid(T2) && fastCopy) {
            // We're copying like datatypes so use memcpy for speed
            for (i1=src.row_begin(), i2=dst.row_begin(); i1 != src.row_end(); i1++, i2++) {
                p1 = i1->p;
                p2 = i2->p;
                memcpy (p2, p1, bytes);
            }
        }
        else {
            // We have to do a pixel by pixel copy
            for (i1=src.row_begin(), i2=dst.row_begin(); i1 != src.row_end(); i1++, i2++) {
                p1 = i1->p;
                p2 = i2->p;
                for (unsigned int x=0; x<w; x++)
                    *p2++ = static_cast<T2>(*p1++);
            }
        }
    }


    template <class T>
    ImageStorage<T> duplicate (const ImageStorage<T>& src, 
                                 RectImageStorage::eAlignment align)
    {
        ImageStorage<T> dst (src.boundary(), align);

        copy (src, dst);
        return dst;
    }


}

#endif // _imageStorageTmpl_h_
